home *** CD-ROM | disk | FTP | other *** search
/ Reverse Code Engineering RCE CD +sandman 2000 / ReverseCodeEngineeringRceCdsandman2000.iso / RCE / Library / Manuels & Misc / Assembly / AOA.ZIP / CH20 / INT16.ASM < prev    next >
Encoding:
Assembly Source File  |  1994-07-22  |  9.1 KB  |  365 lines

  1. ; INT16.ASM
  2. ;
  3. ; A short passive TSR that replaces the BIOS' int 16h handler.
  4. ; This routine demonstrates the function of each of the int 16h
  5. ; functions that a standard BIOS would provide.
  6. ;
  7. ; Note that this code does not patch into int 2Fh (multiplex interrupt)
  8. ; nor can you remove this code from memory except by rebooting.
  9. ; If you want to be able to do these two things (as well as check for
  10. ; a previous installation), see the chapter on resident programs.  Such
  11. ; code was omitted from this program because of length constraints.
  12. ;
  13. ;
  14. ; cseg and EndResident must occur before the standard library segments!
  15.  
  16. cseg        segment    para public 'code'
  17. cseg        ends
  18.  
  19. ; Marker segment, to find the end of the resident section.
  20.  
  21. EndResident    segment    para public 'Resident'
  22. EndResident    ends
  23.  
  24.         .xlist
  25.         include     stdlib.a
  26.         includelib    stdlib.lib
  27.         .list
  28.  
  29.  
  30. byp        equ    <byte ptr>
  31.  
  32. cseg        segment    para public 'code'
  33.         assume    cs:cseg, ds:cseg
  34.  
  35. OldInt16    dword    ?
  36.  
  37.  
  38. ; BIOS variables:
  39.  
  40. KbdFlags1    equ    <ds:[17h]>
  41. KbdFlags2    equ    <ds:[18h]>
  42. AltKpd        equ    <ds:[19h]>
  43. HeadPtr        equ    <ds:[1ah]>
  44. TailPtr        equ    <ds:[1ch]>
  45. Buffer        equ    1eh
  46. EndBuf        equ    3eh
  47.  
  48. KbdFlags3    equ    <ds:[96h]>
  49. KbdFlags4    equ    <ds:[97h]>
  50.  
  51. incptr        macro    which
  52.         local    NoWrap
  53.         add    bx, 2
  54.         cmp    bx, EndBuf
  55.         jb    NoWrap
  56.         mov    bx, Buffer
  57. NoWrap:        mov    which, bx
  58.         endm
  59.  
  60.  
  61. ; MyInt16-    This routine processes the int 16h function requests.
  62. ;
  63. ;        AH    Description
  64. ;        --    ------------------------------------------------
  65. ;        00h    Get a key from the keyboard, return code in AX.
  66. ;        01h    Test for available key, ZF=1 if none, ZF=0 and
  67. ;            AX contains next key code if key available.
  68. ;        02h    Get shift status.  Returns shift key status in AL.
  69. ;        03h    Set Autorepeat rate.  BH=0,1,2,3 (delay time in
  70. ;            quarter seconds), BL=0..1Fh for 30 char/sec to
  71. ;            2 char/sec repeat rate.
  72. ;        05h    Store scan code (in CX) in the type ahead buffer.
  73. ;        10h    Get a key (same as 00h in this implementation).
  74. ;        11h    Test for key (same as 01h).
  75. ;        12h    Get extended key status.  Returns status in AX.
  76.  
  77.  
  78. MyInt16        proc    far
  79.         test    ah, 0EFh        ;Check for 0h and 10h
  80.         je    GetKey
  81.         cmp    ah, 2            ;Check for 01h and 02h
  82.         jb    TestKey
  83.         je    GetStatus
  84.         cmp    ah, 3            ;Check for AutoRpt function.
  85.         je    SetAutoRpt
  86.         cmp    ah, 5            ;Check for StoreKey function.
  87.         je    StoreKey
  88.         cmp    ah, 11h            ;Extended test key opcode.
  89.         je    TestKey
  90.         cmp    ah, 12h            ;Extended status call
  91.         je    ExtStatus
  92.  
  93. ; Well, it's a function we don't know about, so just return to the caller.
  94.  
  95.         iret
  96.  
  97. ; If the user specified ah=0 or ah=10h, come down here (we will not
  98. ; differentiate between extended and original PC getc calls).
  99.  
  100. GetKey:        mov    ah, 11h
  101.         int    16h            ;See if key is available.
  102.         je    GetKey            ;Wait for keystroke.
  103.  
  104.         push    ds
  105.         push    bx
  106.         mov    ax, 40h
  107.         mov    ds, ax
  108.         cli                ;Critical region! Ints off.
  109.         mov    bx, HeadPtr        ;Ptr to next character.
  110.         mov    ax, [bx]        ;Get the character.
  111.         incptr    HeadPtr            ;Bump up HeadPtr
  112.         pop    bx
  113.         pop    ds
  114.         iret                ;Restores interrupt flag.
  115.  
  116. ; TestKey-     Checks to see if a key is available in the keyboard buffer.
  117. ;               We need to turn interrupts on here (so the kbd ISR can
  118. ;        place a character in the buffer if one is pending).
  119. ;        Generally, you would want to save the interrupt flag here.
  120. ;        But BIOS always forces interrupts on, so there may be some
  121. ;        programs out there that depend on this, so we won't "fix"
  122. ;        this problem.
  123. ;
  124. ;        Returns key status in ZF and AX.  If ZF=1 then no key is
  125. ;        available and the value in AX is indeterminate.  If ZF=0
  126. ;        then a key is available and AX contains the scan/ASCII
  127. ;        code of the next available key.  This call does not remove
  128. ;        the next character from the input buffer.
  129.  
  130. TestKey:    sti                ;Turn on the interrupts.
  131.         push    ds
  132.         push    bx
  133.         mov    ax, 40h
  134.         mov    ds, ax
  135.         cli                ;Critical region, ints off!
  136.         mov    bx, HeadPtr
  137.         mov    ax, [bx]        ;BIOS returns avail keycode.
  138.         cmp    bx, TailPtr        ;ZF=1, if empty buffer
  139.         pop    bx
  140.         pop    ds
  141.         sti                ;Inst back on.
  142.         retf    2            ;Pop flags (ZF is important!)
  143.  
  144.  
  145. ; The GetStatus call simply returns the KbdFlags1 variable in AL.
  146.  
  147. GetStatus:    push    ds
  148.         mov    ax, 40h
  149.         mov    ds, ax
  150.         mov    al, KbdFlags1        ;Just return Std Status.
  151.         pop    ds
  152.         iret
  153.  
  154.  
  155. ; StoreKey-    Inserts the value in CX into the type ahead buffer.
  156.  
  157. StoreKey:    push    ds
  158.         push    bx
  159.         mov    ax, 40h
  160.         mov    ds, ax
  161.         cli                ;Ints off, critical region.
  162.         mov    bx, TailPtr        ;Address where we can put
  163.         push    bx            ; next key code.
  164.         mov    [bx], cx        ;Store the key code away.
  165.         incptr     TailPtr            ;Move on to next entry in buf.
  166.         cmp    bx, HeadPtr        ;Data overrun?
  167.         jne    StoreOkay        ;If not, jump, if so
  168.         pop    TailPtr            ; ignore key entry.
  169.         sub    sp, 2            ;So stack matches alt path.
  170. StoreOkay:    add    sp, 2            ;Remove junk data from stk.
  171.         pop    bx
  172.         pop    ds
  173.         iret                ;Restores interrupts.
  174.  
  175.  
  176. ; ExtStatus-    Retrieve the extended keyboard status and return it in
  177. ;        AH, also returns the standard keyboard status in AL.
  178.  
  179. ExtStatus:    push    ds
  180.         mov    ax, 40h
  181.         mov    ds, ax
  182.  
  183.         mov    ah, KbdFlags2
  184.         and    ah, 7Fh            ;Clear final sysreq field.
  185.         test    ah, 100b        ;Test cur sysreq bit.
  186.         je    NoSysReq        ;Skip if it's zero.
  187.         or    ah, 80h            ;Set final sysreq bit.
  188. NoSysReq:
  189.         and    ah, 0F0h        ;Clear alt/ctrl bits.
  190.         mov    al, KbdFlags3
  191.         and    al, 1100b        ;Grab rt alt/ctrl bits.
  192.         or    ah, al            ;Merge into AH.
  193.         mov    al, KbdFlags2
  194.         and    al, 11b            ;Grab left alt/ctrl bits.
  195.         or    ah, al            ;Merge into AH.
  196.  
  197.         mov    al, KbdFlags1        ;AL contains normal flags.
  198.         pop    ds
  199.         iret
  200.  
  201. ; SetAutoRpt-    Sets the autorepeat rate.  On entry, bh=0, 1, 2, or 3 (delay
  202. ;        in 1/4 sec before autorepeat starts) and bl=0..1Fh (repeat
  203. ;        rate, about 2:1 to 30:1 (chars:sec).
  204.  
  205. SetAutoRpt:     push    cx
  206.         push    bx
  207.  
  208.         mov    al, 0ADh        ;Disable kbd for now.
  209.         call    SetCmd
  210.  
  211.         and    bh, 11b            ;Force into proper range.
  212.         mov    cl, 5
  213.         shl    bh, cl            ;Move to final position.
  214.         and    bl, 1Fh            ;Force into proper range.
  215.         or    bh, bl            ;8042 command data byte.
  216.         mov    al, 0F3h        ;8042 set repeat rate cmd.
  217.         call    SendCmd            ;Send the command to 8042.
  218.         mov    al, bh            ;Get parameter byte
  219.         call    SendCmd            ;Send parameter to the 8042.
  220.  
  221.         mov    al, 0AEh        ;Reenable keyboard.
  222.         call    SetCmd
  223.         mov    al, 0F4h        ;Restart kbd scanning.
  224.         call    SendCmd
  225.  
  226.         pop    bx
  227.         pop    cx
  228.         iret
  229.  
  230. MyInt16        endp
  231.  
  232.  
  233.  
  234. ; SetCmd-    Sends the command byte in the AL register to the 8042
  235. ;        keyboard microcontroller chip (command register at
  236. ;        port 64h).
  237.  
  238. SetCmd        proc    near
  239.         push    cx
  240.         push    ax        ;Save command value.
  241.         cli            ;Critical region, no ints now.
  242.  
  243. ; Wait until the 8042 is done processing the current command.
  244.  
  245.         xor    cx, cx        ;Allow 65,536 times thru loop.
  246. Wait4Empty:    in    al, 64h        ;Read keyboard status register.
  247.         test    al, 10b        ;Input buffer full?
  248.         loopnz    Wait4Empty    ;If so, wait until empty.
  249.  
  250. ; Okay, send the command to the 8042:
  251.  
  252.         pop    ax        ;Retrieve command.
  253.         out    64h, al
  254.         sti            ;Okay, ints can happen again.
  255.         pop    cx
  256.         ret
  257. SetCmd        endp
  258.  
  259.  
  260.  
  261.  
  262. ; SendCmd-    The following routine sends a command or data byte to the
  263. ;        keyboard data port (port 60h).
  264.  
  265. SendCmd        proc    near
  266.         push    ds
  267.         push    bx
  268.         push    cx
  269.         mov    cx, 40h
  270.         mov    ds, cx
  271.         mov    bx, ax        ;Save data byte
  272.  
  273.         mov    bh, 3        ;Retry cnt.
  274. RetryLp:    cli            ;Disable ints while accessing HW.
  275.  
  276. ; Clear the Error, Acknowledge received, and resend received flags
  277. ; in KbdFlags4
  278.  
  279.         and    byte ptr KbdFlags4, 4fh
  280.  
  281. ; Wait until the 8042 is done processing the current command.
  282.  
  283.         xor    cx, cx            ;Allow 65,536 times thru loop.
  284. Wait4Empty:    in    al, 64h            ;Read keyboard status register.
  285.         test    al, 10b            ;Input buffer full?
  286.         loopnz    Wait4Empty        ;If so, wait until empty.
  287.  
  288. ; Okay, send the data to port 60h
  289.  
  290.         mov    al, bl
  291.         out    60h, al
  292.         sti                ;Allow interrupts now.
  293.  
  294. ; Wait for the arrival of an acknowledgement from the keyboard ISR:
  295.  
  296.         xor    cx, cx            ;Wait a long time, if need be.
  297. Wait4Ack:    test    byp KbdFlags4, 10h    ;Acknowledge received bit.
  298.         jnz    GotAck
  299.         loop    Wait4Ack
  300.         dec    bh            ;Do a retry on this guy.
  301.         jne     RetryLp
  302.  
  303. ; If the operation failed after 3 retries, set the error bit and quit.
  304.  
  305.         or    byp KbdFlags4, 80h    ;Set error bit.
  306.  
  307. GotAck:        pop    cx
  308.         pop    bx
  309.         pop    ds
  310.         ret
  311. SendCmd        endp
  312.  
  313.  
  314.  
  315. Main        proc
  316.  
  317.         mov    ax, cseg
  318.         mov    ds, ax
  319.  
  320.         print
  321.         byte    "INT 16h Replacement",cr,lf
  322.         byte    "Installing....",cr,lf,0
  323.  
  324. ; Patch into the INT 9 and INT 16 interrupt vectors.  Note that the
  325. ; statements above have made cseg the current data segment,
  326. ; so we can store the old INT 9 and INT 16 values directly into
  327. ; the OldInt9 and OldInt16 variables.
  328.  
  329.         cli                ;Turn off interrupts!
  330.         mov    ax, 0
  331.         mov    es, ax
  332.         mov    ax, es:[16h*4]
  333.         mov    word ptr OldInt16, ax
  334.         mov     ax, es:[16h*4 + 2]
  335.         mov    word ptr OldInt16+2, ax
  336.         mov    es:[16h*4], offset MyInt16
  337.         mov    es:[16h*4+2], cs
  338.         sti                ;Okay, ints back on.
  339.  
  340.  
  341. ; We're hooked up, the only thing that remains is to terminate and
  342. ; stay resident.
  343.  
  344.         print
  345.         byte    "Installed.",cr,lf,0
  346.  
  347.         mov    ah, 62h            ;Get this program's PSP
  348.         int    21h            ; value.
  349.  
  350.         mov    dx, EndResident        ;Compute size of program.
  351.         sub    dx, bx
  352.         mov    ax, 3100h        ;DOS TSR command.
  353.         int    21h
  354. Main        endp
  355. cseg        ends
  356.  
  357. sseg        segment    para stack 'stack'
  358. stk        db    1024 dup ("stack   ")
  359. sseg        ends
  360.  
  361. zzzzzzseg    segment    para public 'zzzzzz'
  362. LastBytes    db    16 dup (?)
  363. zzzzzzseg    ends
  364.         end    Main
  365.